"""
实验数据性能指标计算工具
用于计算输出功率和Fy的时间积分，并进行对比分析
"""

import logging
from pathlib import Path

import numpy as np
import pandas as pd
from scipy import signal

# 设置日志
logging.basicConfig(
    level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
)
logger = logging.getLogger(__name__)

# === 常量定义 ===
DEFAULT_SAMPLING_RATES = {"0x61": 500, "0x22": 640, "0x33": 10}
DEFAULT_TIME_LENGTH = 6000
RPM_TIME_LENGTH_MAPPING = {
    30: 6000,
    45: 4000,
    60: 3000,
    75: 2500,
    90: 2000,
    105: 1800,
    120: 1500,
    135: 1300,
}

# === 信号处理函数（从single_plot.py复制） ===


def filter_and_scale_angle(
    angle_data: np.ndarray,
    cutoff_freq: int,
    target_amplitude: float,
    sampling_rate: int = 640,
) -> np.ndarray:
    """对angle数据进行滤波和缩放处理"""
    angle = np.array(angle_data, dtype=float)

    try:
        # 1. 低通滤波去除高频噪声
        nyquist = sampling_rate / 2
        normalized_cutoff = cutoff_freq / nyquist

        if normalized_cutoff >= 1:
            normalized_cutoff = 0.9
            logger.warning(
                f"截止频率过高，调整为 {normalized_cutoff * nyquist:.1f} Hz"
            )

        b, a = signal.butter(
            N=4, Wn=normalized_cutoff, btype="lowpass", output="ba"
        )
        filtered_angle = signal.filtfilt(b=b, a=a, x=angle, method="gust")

        # 2. 去直流分量
        dc_offset = np.mean(filtered_angle)
        centered_angle = filtered_angle - dc_offset

        # 3. 缩放到目标幅值
        current_amplitude = np.max(np.abs(centered_angle))
        if current_amplitude > 0:
            scale_factor = target_amplitude / current_amplitude
            scaled_angle = centered_angle * scale_factor
        else:
            scaled_angle = centered_angle
            logger.warning("angle数据幅值为0，无法进行缩放")

        return scaled_angle

    except Exception as e:
        logger.error(f"角度滤波和缩放处理失败: {e}")
        return angle_data


def lowpass_filter(
    data: np.ndarray, cutoff_freq: int, sampling_rate: int = 640
) -> np.ndarray:
    """对信号进行低通滤波"""
    x = np.array(data, dtype=float)

    try:
        nyquist = sampling_rate / 2
        normalized_cutoff = cutoff_freq / nyquist

        if normalized_cutoff >= 1:
            normalized_cutoff = 0.9
            logger.warning(
                f"滤波截止频率过高，调整为 {normalized_cutoff * nyquist:.1f} Hz"
            )

        b, a = signal.butter(
            N=4, Wn=normalized_cutoff, btype="lowpass", output="ba"
        )
        filtered_data = signal.filtfilt(b=b, a=a, x=x, method="gust")

        return np.array(filtered_data)

    except Exception as e:
        logger.error(f"低通滤波处理失败: {e}")
        return data


def calculate_angular_velocity(
    angle: np.ndarray, t22: np.ndarray
) -> np.ndarray:
    """计算角速度"""
    angle_rad = np.deg2rad(angle)
    dt = np.diff(t22) / 1000.0
    angular_velocity = np.diff(angle_rad) / dt
    angular_velocity = np.concatenate(
        [[angular_velocity[0]], angular_velocity]
    )
    return lowpass_filter(angular_velocity, cutoff_freq=90, sampling_rate=320)


# === 数据加载和处理函数 ===


def load_excel_sheets(filepath: Path) -> dict[str, pd.DataFrame]:
    """加载Excel文件的所有工作表"""
    try:
        xl = pd.ExcelFile(filepath)
        sheets = {}
        for name in xl.sheet_names:
            sheets[name] = xl.parse(name)
        return sheets
    except Exception as e:
        logger.error(f"加载Excel文件失败: {e}")
        raise


def parse_filename(filename: str) -> dict[str, int]:
    """
    解析文件名，提取前置参数和RPM值

    Args:
        filename: 文件名（不含扩展名），如 "75-30-30-75-120RPM"

    Returns:
        前置参数字符串和RPM值
    """
    parts = filename.split("-")
    if len(parts) < 5:
        raise ValueError(f"文件名格式不正确: {filename}")

    # RPM值: 最后一部分
    rpm_value = int(parts[-1].replace("RPM", ""))

    params = {
        "t1": int(parts[0]),
        "t2": int(parts[1]),
        "t3": int(parts[2]),
        "t4": int(parts[3]),
        "rpm": rpm_value,
    }

    return params


def calculate_time_indices(
    sheets: dict[str, pd.DataFrame], start_time: int, time_length: int
) -> tuple[dict[str, int], dict[str, int]]:
    """计算各工作表的开始和结束索引"""
    pc_timestamp_start = sheets["0x61"]["pc_timestamp"].iloc[0] + start_time
    pc_timestamp_end = pc_timestamp_start + time_length

    start_indices = {}
    end_indices = {}

    for key in DEFAULT_SAMPLING_RATES.keys():
        if key in sheets:
            df = sheets[key]
            start_index = (
                (df["pc_timestamp"] - pc_timestamp_start).abs().idxmin()
            )
            end_index = (df["pc_timestamp"] - pc_timestamp_end).abs().idxmin()
            start_indices[key] = start_index
            end_indices[key] = end_index

    return start_indices, end_indices


def process_single_file(
    excel_path: Path, start_time: int, time_length: int
) -> dict[str, float]:
    """
    处理单个Excel文件，计算性能指标

    Args:
        excel_path: Excel文件路径
        start_time: 开始时间偏移量 (ms)
        time_length: 时间长度 (ms)

    Returns:
        包含积分结果的字典
    """

    # === 加载数据 ===
    sheets = load_excel_sheets(excel_path)
    start_indices, end_indices = calculate_time_indices(
        sheets, start_time, time_length
    )

    # === 提取数据 ===
    Fy = np.array(sheets["0x61"]["Fy"])[
        start_indices["0x61"] : end_indices["0x61"]
    ]
    Fx = np.array(sheets["0x61"]["Fx"])[
        start_indices["0x61"] : end_indices["0x61"]
    ]
    weight = np.array(sheets["0x22"]["weight"])[
        start_indices["0x22"] : end_indices["0x22"]
    ]
    angle_raw = np.array(sheets["0x22"]["angle"])[
        start_indices["0x22"] : end_indices["0x22"]
    ]

    # === 计算时间轴 ===
    t61 = np.array(sheets["0x61"]["rdt_sequence"])[
        start_indices["0x61"] : end_indices["0x61"]
    ]
    t61 = (
        t61 - sheets["0x61"]["rdt_sequence"].iloc[start_indices["0x61"]]
    ) * 2
    t22 = np.array(sheets["0x22"]["timestamp"])[
        start_indices["0x22"] : end_indices["0x22"]
    ]
    t22 = t22 - sheets["0x22"]["timestamp"].iloc[start_indices["0x22"]]

    # === 数据后处理 ===

    # 角度传感器数据（模拟量获取到的电压）：去除直流分量、缩放到±30度、低通滤波
    angle = filter_and_scale_angle(
        angle_raw, cutoff_freq=15, target_amplitude=30.0, sampling_rate=640
    )

    # ATI传感器推力方向/横向力方向：低通滤波
    Fy = lowpass_filter(Fy, cutoff_freq=120, sampling_rate=500)
    Fx = lowpass_filter(Fx, cutoff_freq=120, sampling_rate=500)

    # 轴上输出力矩传感器（悬臂梁测得的力：牛顿）：低通滤波
    weight = lowpass_filter(weight, cutoff_freq=60, sampling_rate=640)

    # 根据角度传感器的数据计算角速度并低通滤波
    angular_velocity = calculate_angular_velocity(angle, t22)
    angular_velocity = lowpass_filter(
        angular_velocity, cutoff_freq=10, sampling_rate=640
    )

    # 计算输出至尾鳍的功率（瓦）
    output_power = weight * angular_velocity * 44.88e-3  # 输出功率计算
    output_power = lowpass_filter(
        output_power, cutoff_freq=60, sampling_rate=640
    )

    # === 计算积分（使用梯形法则） ===
    # 时间单位转换为秒
    t61_s = t61 / 1000.0
    t22_s = t22 / 1000.0

    # 计算Fy积分（只保留Fy<0的部分，然后取负数）
    # 由于主体数据Fy<0，我们只保留负值部分进行积分
    fy_negative = np.where(Fy < 0, Fy, 0)  # 保留负值，正值设为0
    fy_integral = -np.trapezoid(
        fy_negative, t61_s
    )  # 积分后取负数，得到的fy_integral为正值
    fx_abs = np.abs(Fx)
    fx_abs_integral = np.trapezoid(fx_abs, t61_s)

    # 计算输出功率积分（取绝对值）
    power_integral = np.trapezoid(np.abs(output_power), t22_s)

    # 计算单位时间内的积分值（用于不同时间长度的比较）
    actual_time_length_s = time_length / 1000.0  # 实际时间长度（秒）
    fy_integral_per_second = (
        fy_integral / actual_time_length_s
    )  # 平均fy积分（每秒）
    power_integral_per_second = (
        power_integral / actual_time_length_s
    )  # 平均功率（每秒）

    # 计算效率：Fy积分与输出功率积分的比值
    efficiency = fy_integral / power_integral if power_integral > 0 else 0.0

    metrics = {
        "fy_integral": fy_integral,  # 取样时间内总计Fy积分
        "fx_abs_integral": fx_abs_integral,  # 取样时间内总计|Fx|积分
        "power_integral": power_integral,  # 取样时间内总计做功
        "fy_integral_per_second": fy_integral_per_second,  # 单位时间内平均Fy积分
        "power_integral_per_second": power_integral_per_second,  # 单位时间内平均做功
        "efficiency": efficiency,  # 总效率
        "avg_fy": np.mean(np.abs(Fy)),  # 平均Fy
        "avg_power": np.mean(np.abs(output_power)),  # 平均功率
    }

    return metrics


def analyze_datafile(filepath: Path) -> tuple[dict, dict]:
    # 解析文件名
    params = parse_filename(filepath.stem)
    # 确定取样时间长度
    time_length = RPM_TIME_LENGTH_MAPPING.get(
        params["rpm"], DEFAULT_TIME_LENGTH
    )

    logger.info(
        f"前置参数:{params['t1']} {params['t2']} {params['t3']} {params['t4']}\
        RPM:{params['rpm']}, 时间长度:{time_length}ms"
    )

    # 计算性能指标
    metrics = process_single_file(filepath, 500, time_length)

    return params, metrics


def ax_metrics_from_file(
    filepath: Path, metric: str, motor_rpm: int
) -> dict[str, float]:
    """
    从Excel文件计算Ax优化所需的性能指标

    Args:
        filepath: Excel文件路径
        metric: 需要计算的指标名称
    Returns:
        包含Ax优化指标的字典，如 {"efficiency": 0.85}
    """
    _, metrics_dict = analyze_datafile(filepath)
    # 返回用于Ax优化的指标
    return {f"{metric}_{motor_rpm}rpm": metrics_dict[metric]}
